﻿#include "C3fdTecplotAsciiFileReader.h"
#include <QFile>
#include <QDebug>
#include <vtkNew.h>
#include <vtkPoints.h>
#include <QFileInfo>
#include <QTextStream>

namespace MainWidget
{
	C3fdTecDatObject *C3fdTecplotAsciiFileReader::parse(QString fileName)
	{
		C3fdTecDatObject *datObject = nullptr;
		QFile datFile(fileName);
		if (datFile.open(QIODevice::ReadOnly | QIODevice::Text))
		{
			datObject = new C3fdTecDatObject;

			QTextStream dat(&datFile);
			QString line = dat.readLine().simplified();
			int zoneIndex = 0;
			while (!line.isNull())
			{
				if (line.startsWith("TITLE"))
				{
					datObject->setTitle(line.mid(6).remove(QChar('"')).remove(QChar(' ')));
				}
				else if (line.startsWith("VARIABLES"))
				{
					datObject->setVariables(line.mid(10).remove(QChar('"')).remove(QChar(' ')).split(","));
				}
				else if (line.startsWith("ZONE"))
				{
					auto *datZone = new C3fdTecDatZone;
					auto zoneProperty = readZoneProperty(line);
					bool ok;
					int zoneI = zoneProperty.value("I").toInt(&ok);
					if (!ok)
					{
						break;
					}
					int zoneJ = zoneProperty.value("J").toInt(&ok);
					if (!ok)
					{
						break;
					}

					if (zoneProperty.contains("K"))
					{
						int zoneK = zoneProperty.value("K").toInt(&ok);
						if (!ok)
						{
							break;
						}
						datZone->setDimK(zoneK);
					}

					datZone->setDimI(zoneI);
					datZone->setDimJ(zoneJ);
					if (zoneProperty.contains("T"))
					{
						datZone->setTitle(zoneProperty.value("T"));
					}

					if (zoneProperty.contains("DATAPACKING") && zoneProperty.value("DATAPACKING") == "BLOCK")
					{
						datZone->setPackingMethod(PackingMethod::BLOCK);

						datZone->setValLocations(parseVarLocation(zoneProperty.value("VARLOCATION")));
						datZone->set3DPoint(!datZone->getValLocations().contains(3));

						datZone->setDatas(readBlockPackingZoneData(dat, zoneI, zoneJ, datZone->getDimK(), datObject->getVariables().size(), datZone->getValLocations()));
					}
					else
					{
						datZone->setPackingMethod(PackingMethod::POINT);

						datZone->set3DPoint(datObject->getVariables().contains("Z"));

						datZone->setDatas(readPointPackingZoneData(dat, zoneI, zoneJ, datZone->getDimK(), datObject->getVariables().size()));
					}

					datObject->addZone(datZone);
				}
				line = dat.readLine().simplified();
			}
		}
		else
		{
			qDebug() << "Failed to open file: " << fileName;
		}

		return datObject;
	}

	QHash<QString, QString> C3fdTecplotAsciiFileReader::readZoneProperty(QString line)
	{
		QHash<QString, QString> props = {};
		QStringList tempLines = line.mid(4).remove(QChar('"')).remove(QChar(' ')).split(",");
		for (QString tempLine : tempLines)
		{
			auto ps = tempLine.split("=");
			if (ps.size() == 2)
			{
				props.insert(ps.at(0).simplified(), ps.at(1).simplified());
			}
			else if (ps.size() > 2)
			{
				props.insert(ps.at(0).simplified(), ps.mid(1).join("=").simplified());
			}
		}
		return props;
	}

	QHash<int, ValLocation> C3fdTecplotAsciiFileReader::parseVarLocation(QString varlocation)
	{
		QHash<int, ValLocation> result;
		QString cellValStr = "", nodeValStr = "";
		auto locs = varlocation.remove(QChar('(')).remove(QChar(')')).split(",");
		for (auto l : locs)
		{
			auto items = l.split("=");
			if (items.size() == 2)
			{
				if (items.at(1) == "CELLCENTERED")
				{
					cellValStr = items.at(0);
				}
				else if (items.at(1) == "NODAL")
				{
					nodeValStr = items.at(0);
				}
			}
		}

		if (!cellValStr.isEmpty())
		{
			auto items = cellValStr.remove(QChar('[')).remove(QChar(']')).remove(QChar(' ')).split(",");
			for (auto item : items)
			{
				auto ites = item.trimmed().split("-");
				QList<QString> orders = {};
				if (ites.size() == 2)
				{
					bool ok1, ok2;
					int start = ites.at(0).toInt(&ok1);
					int end = ites.at(1).toInt(&ok2);
					if (ok1 && ok2)
					{
						for (int i = start; i <= end; ++i)
						{
							result.insert(i, ValLocation::CELLCENTERED);
						}
					}
				}
				else if (ites.size() == 1)
				{
					bool ok;
					int order = ites.at(0).toInt(&ok);
					if (ok)
					{
						result.insert(order, ValLocation::CELLCENTERED);
					}
				}
			}
		}

		if (!nodeValStr.isEmpty())
		{
			auto items = nodeValStr.remove(QChar('[')).remove(QChar(']')).remove(QChar(' ')).split(",");
			for (auto item : items)
			{
				auto ites = item.trimmed().split("-");
				QList<QString> orders = {};
				if (ites.size() == 2)
				{
					bool ok1, ok2;
					int start = ites.at(0).toInt(&ok1);
					int end = ites.at(1).toInt(&ok2);
					if (ok1 && ok2)
					{
						for (int i = start; i <= end; ++i)
						{
							result.insert(i, ValLocation::NODAL);
						}
					}
				}
				else if (ites.size() == 1)
				{
					bool ok;
					int order = ites.at(0).toInt(&ok);
					if (ok)
					{
						result.insert(order, ValLocation::NODAL);
					}
				}
			}
		}

		return result;
	}

	QList<QVector<double>> C3fdTecplotAsciiFileReader::readPointPackingZoneData(QTextStream &dat, int ix, int jy, int kz, int eachRowItemNum)
	{
		QList<QVector<double>> data{};
		int totalRow = ix * jy * kz;
		QString line = "";
		QStringList lineItems = {};
		for (int i = 0; i < totalRow; i++)
		{
			line = dat.readLine().simplified();
			lineItems = line.split(' ');
			if (lineItems.size() != eachRowItemNum)
			{
				break;
			}

			QVector<double> row = {};
			bool ok;
			for (int i = 0; i < eachRowItemNum; i++)
			{
				double value = lineItems.at(i).toDouble(&ok);
				if (ok)
				{
					row.push_back(value);
				}
			}
			data.push_back(row);
		}
		return data;
	}

	QList<QVector<double>> C3fdTecplotAsciiFileReader::readBlockPackingZoneData(QTextStream &dat, int ix, int jy, int kz, int numOfVar, QHash<int, ValLocation> locs)
	{
		QList<QVector<double>> data{};
		int totalNum = 1;
		QStringList lineItems = {};
		int eachRowItemNum = 0;
		bool ok;
		for (int i = 0; i < numOfVar; i++)
		{
			if (locs.contains(i + 1) && locs.value(i + 1) == ValLocation::CELLCENTERED)
			{
				totalNum = 1;
				totalNum *= ix > 1 ? ix - 1 : 1;
				totalNum *= jy > 1 ? jy - 1 : 1;
				totalNum *= kz > 1 ? kz - 1 : 1;
			}
			else
			{
				totalNum = ix * jy * kz;
			}
			int num = 0;
			QVector<double> row = {};
			while (num < totalNum && !dat.atEnd())
			{
				lineItems = dat.readLine().simplified().split(" ");
				eachRowItemNum = lineItems.size();
				for (int i = 0; i < eachRowItemNum; i++)
				{
					double value = lineItems.at(i).toDouble(&ok);
					if (ok)
					{
						row.push_back(value);
					}
				}
				num += eachRowItemNum;
			}
			data.push_back(row);
		}
		return data;
	}

}